package com.yy.QSManage.api;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yy.QSManage.common.Result;
import com.yy.QSManage.exception.ServiceException;
import com.yy.QSManage.model.dto.OptionsDto;
import com.yy.QSManage.model.entity.FaSysFile;
import com.yy.QSManage.model.entity.FaSysGrid;
import com.yy.QSManage.model.entity.FaSysImportRecord;
import com.yy.QSManage.model.validatio.Create;
import com.yy.QSManage.model.validatio.Update;
import com.yy.QSManage.service.*;
import com.yy.QSManage.service.base.BaseService;
import com.yy.QSManage.tool.ExcelTool;
import com.yy.QSManage.tool.RequestBuffUtil;
import com.yy.QSManage.tool.TreeNode;
import com.yy.QSManage.tool.TreeUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.baomidou.mybatisplus.extension.toolkit.Db.updateById;

@Slf4j
public class BaseApi<T> {

    @Autowired(required = false)
    public BaseService<T> baseService;

    @Autowired
    FaSysGridService gridService;

    @Autowired
    FaSysFileService fileService;

    @Autowired
    FaSysImportRecordService importRecordService;

    @Autowired
    FaSysOptionService optionService;

    @Autowired
    private FaSysMemberService memberService;

    @ApiOperation("分页")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "第几页", required = true, dataType = "Integer", paramType = "path"),
            @ApiImplicitParam(name = "pageSize", value = "每页数量", required = true, dataType = "Integer", paramType = "path"),
            @ApiImplicitParam(name = "query", value = "查询参数", required = true, dataType = "T", paramType = "body")
    })
    @PostMapping("/page/{pageNum}/{pageSize}")
    public Result<IPage<T>> page(@PathVariable Integer pageNum,
                                 @PathVariable Integer pageSize,
                                 @RequestBody T query){
        FaSysGrid grid = gridService.getById(RequestBuffUtil.getGridId());
        return Result.success(baseService.page(new Page<>(pageNum, pageSize), query, grid));
    }

    @ApiOperation("分页-无查询条件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "第几页", required = true, dataType = "Integer", paramType = "path"),
            @ApiImplicitParam(name = "pageSize", value = "每页数量", required = true, dataType = "Integer", paramType = "path")
    })
    @GetMapping("/pageNoSql/{pageNum}/{pageSize}")
    public Result<IPage<T>> pageNoSql(@PathVariable Integer pageNum,
                                      @PathVariable Integer pageSize){
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        return Result.success(baseService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }

    @ApiOperation("列表-无分页")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "query", value = "查询参数", required = true, dataType = "T", paramType = "body")
    })
    @PostMapping("/listNotPage")
    public Result<List<T>> listNotPage(@RequestBody T query){
        FaSysGrid grid = gridService.getById(RequestBuffUtil.getGridId());
        IPage<T> page = baseService.page(new Page(1, Integer.MAX_VALUE), query, grid);
        return Result.success(page.getRecords());
    }

    @ApiOperation("列表")
    @GetMapping("/list")
    public Result<List<T>> list() {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if(existfield("sort")){
            queryWrapper.orderByDesc("sort");
        }else{
            queryWrapper.orderByDesc("update_time");
        }
        List<T> list = baseService.list(queryWrapper);
        return Result.success(list);
    }

    @ApiOperation("树")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "query", value = "查询参数", required = true, dataType = "T", paramType = "body")
    })
    @PostMapping("/tree")
    public Result<List<T>> tree(@RequestBody T query) {
        FaSysGrid grid = gridService.getById(RequestBuffUtil.getGridId());
        IPage<T> page = baseService.page(new Page(1, Integer.MAX_VALUE), query, grid);
        List<T> list = page.getRecords();
        // 判断是否继承TreeNode类
        Class<?> eClass = getEClass();
        if(TreeNode.class.isAssignableFrom(eClass)){
            // 数据转化为树
            list = (List<T>) TreeUtil.build((List<TreeNode>) list);
        }
        return Result.success(list);
    }

    @ApiOperation("树-节点移动")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "类型(top:向上移动,bottom:向下移动,topMost:移动到顶部,bottomMost:移动到底部)", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "String", paramType = "path")
    })
    @GetMapping("/treeMove/{type}/{id}")
    public Result<Boolean> treeMove(@PathVariable String type, @PathVariable String id){
        // 判断id是否存在
        T moveNode = baseService.getById(id);
        // 获取同级列表
        Object pid = ReflectUtil.getFieldValue(moveNode, "pid");
        List<T> nodes = baseService.listByParam("pid", pid);
        int moveSortInt = nodes.indexOf(moveNode);
        T targetNode = null;
        try {
            switch (type){
                case "top":
                    targetNode = nodes.get(moveSortInt - 1);
                    break;
                case "bottom":
                    targetNode = nodes.get(moveSortInt + 1);
                    break;
                case "topMost":
                    targetNode = nodes.get(0);
                    break;
                case "bottomMost":
                    targetNode = nodes.get(nodes.size()-1);
                    break;
            }
        } catch (IndexOutOfBoundsException e) {
            throw new ServiceException("不允许该移动操作！");
        }
        // 与目标对象交换排序
        sortExchange(moveNode, targetNode);
        return Result.success();
    }

    @ApiOperation("节点移动")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "类型(top:向上移动,bottom:向下移动,topMost:移动到顶部,bottomMost:移动到底部)", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "String", paramType = "path")
    })
    @GetMapping("/move/{type}/{id}")
    public Result<Boolean> move(@PathVariable String type, @PathVariable String id){
        // 判断id是否存在
        T moveNode = baseService.getById(id);
        // 获取同级列表
        Object moveSort = ReflectUtil.getFieldValue(moveNode, "sort");
        T targetNode = null;
        switch (type){
            case "top":
                targetNode = baseService.getGtOne("sort", moveSort);
                break;
            case "bottom":
                targetNode = baseService.getLtOne("sort", moveSort);
                break;
            case "topMost":
                targetNode = baseService.getMax("sort");
                break;
            case "bottomMost":
                targetNode = baseService.getMin("sort");
                break;
        }
        // 与目标对象交换排序
        sortExchange(moveNode, targetNode);
        return Result.success();
    }

    @ApiOperation("获取单条")
    @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "String", paramType = "path")
    @GetMapping("/get/{id}")
    public Result<T> get(@PathVariable String id){
        T query = baseService.getById(id);
        // 越权检查
        overstepCheck(query);
        return Result.success(query);
    }

    @ApiOperation("获取单条")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "field", value = "field", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "value", value = "value", required = true, dataType = "String", paramType = "path")
    })
    @GetMapping("/getByParam/{field}/{value}")
    public Result<T> getByParam(@PathVariable String field, @PathVariable String value){
        return Result.success(baseService.getByParam(field, value));
    }

    @ApiOperation("编辑")
    @ApiImplicitParam(name = "query", value = "查询参数", required = true, dataType = "T", paramType = "body")
    @PostMapping("/edit")
    public Result<Boolean> edit(@RequestBody @Validated(Update.class)  T query){
        editBefore(query);
        // 获取网格id
        String gridId = RequestBuffUtil.getGridId();
        // 获取网格信息
        FaSysGrid grid = gridService.getById(gridId);
        String editJson = grid.getEditJson();
        JSONArray editJsonArr = JSONUtil.parseArray(editJson);
        UpdateWrapper<T> updateWrapper = editFieldFilter(query, editJsonArr);
        // 参数校验
        parameterVerification(query, editJsonArr, "EDIT");
        // 自动填充(UpdateWrapper无法使用官方自动填充方法，只能手动设置)
        editAutofill(updateWrapper);
        editAfter(updateWrapper, query);
        return Result.success(baseService.update(updateWrapper));
    }

    /**
     * 编辑自动填充
     * @param updateWrapper
     */
    public void editAutofill(UpdateWrapper<T> updateWrapper){
        updateWrapper.set("update_time", new Date())
                .set("update_user", memberService.getTokenMemberId());
    }

    /**
     * 编辑前置钩子函数
     * @param query
     */
    public void editBefore(T query){

    }

    /**
     * 编辑后置钩子函数
     * @param updateWrapper
     * @return
     */
    public void editAfter(UpdateWrapper<T> updateWrapper, T query){

    }

    @ApiOperation("添加")
    @ApiImplicitParam(name = "query", value = "查询参数", required = true, dataType = "T", paramType = "body")
    @PostMapping("/add")
    public Result<Boolean> add(@RequestBody @Validated(Create.class) T query){
        // 获取网格id
        String gridId = RequestBuffUtil.getGridId();
        // 获取网格信息
        FaSysGrid grid = gridService.getById(gridId);
        // 获取添加配置
        String addJson = grid.getAddJson();
        JSONArray jsonArray = JSONUtil.parseArray(addJson);
        T newQuery = addFieldFilter(query, jsonArray);
        // 参数校验
        parameterVerification(newQuery, jsonArray, "ADD");
        addBefore(query);
        return Result.success(baseService.save(newQuery));
    }

    public void addBefore(T query){

    }

    /**
     * 编辑字段过滤
     * @param query
     * @param fieldJson
     * @return
     */
    private UpdateWrapper<T> editFieldFilter(T query, JSONArray fieldJson){
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", ReflectUtil.getFieldValue(query,"id"));
        for (Object o : fieldJson) {
            JSONObject entries = JSONUtil.parseObj(o);
            // 获取编辑字段名
            String field = entries.getStr("field");
            if("id".equals(field)){
                continue;
            }
            // 判断是否非数据库字段，即（@TableField(exist = false)）
            Field fieldObj = ReflectUtil.getField(query.getClass(), field);
            // 后去获取字段注解@TableField exist的值
            Object annotationValue = AnnotationUtil.getAnnotationValue(fieldObj, TableField.class, "exist");
            if(Objects.nonNull(annotationValue) && annotationValue.equals(false)){
                continue;
            }
            // 驼峰转下划线
            String _field = StrUtil.toUnderlineCase(field);
            // 插入对应字段值
            updateWrapper.set(_field, ReflectUtil.getFieldValue(query,field));
        }
        return updateWrapper;
    }

    /**
     * 添加字段过滤
     * @param query
     * @param fieldJson
     */
    private T addFieldFilter(T query, JSONArray fieldJson){
        // 创建新对象填充过滤后的数据
        T _t = (T)ReflectUtil.newInstanceIfPossible(query.getClass());
        for (Object o : fieldJson) {
            JSONObject entries = JSONUtil.parseObj(o);
            // 获取编辑字段名
            String field = entries.getStr("field");
            Object fieldValue = ReflectUtil.getFieldValue(query, field);
            ReflectUtil.setFieldValue(_t, field, fieldValue);
        }
        return _t;
    }

    /**
     * 参数校验
     * @param query 数据
     * @param jsonArray 字段配置
     * @param mode 模式（ADD/EDIT）
     */
    private void parameterVerification(T query, JSONArray jsonArray, String mode){
        for (Object fieldObj : jsonArray) {
            JSONObject fieldJsonObj = JSONUtil.parseObj(fieldObj);
            String field = fieldJsonObj.getStr("field");
            // 规则校验
            JSONObject rule = fieldJsonObj.getJSONObject("serviceRule");
            String required = rule.getStr("required");
            String repeat = rule.getStr("repeat");
            Object fieldValue = ReflectUtil.getFieldValue(query, field);
            if("true".equals(required)){
                if(Objects.isNull(fieldValue) || StrUtil.isBlank(fieldValue.toString())){
                    throw new ServiceException("参数必填 ".concat(field));
                }
            } else if (Objects.isNull(fieldValue) || StrUtil.isBlank(fieldValue.toString())) {
                // 值为空，且非必填，跳过以下教校验
                continue;
            }
            // 不允许重复参数必须设置为必填
            if("false".equals(repeat)){
                boolean ifExist;
                if(mode.equals("ADD")){
                    // 查询数据库是否存在重复元素
                    ifExist = baseService.ifExist(StrUtil.toUnderlineCase(field), fieldValue);
                }else {
                    String id = ReflectUtil.getFieldValue(query, "id").toString();
                    ifExist = baseService.ifRepeatExcludeId(StrUtil.toUnderlineCase(field), fieldValue, id);
                }
                if(ifExist){
                    throw new ServiceException("该字段已存在 ".concat(field).concat(":").concat(fieldValue.toString()));
                }
            }
        }
    }

    @ApiOperation("复制")
    @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "String", paramType = "path")
    @GetMapping("/copy/{id}")
    public Result<Boolean> copy(@PathVariable String id){
        T query = baseService.getById(id);
        ReflectUtil.setFieldValue(query,"id", IdUtil.fastSimpleUUID());
        ReflectUtil.setFieldValue(query,"createTime", null);
        ReflectUtil.setFieldValue(query,"updateTime", null);
        baseService.save(query);
        return Result.success();
    }

    @ApiOperation("删除")
    @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "String", paramType = "path")
    @GetMapping("/del/{id}")
    public Result<Boolean> del(@PathVariable String id){
        T query = baseService.getById(id);
        // 越权检查
        overstepCheck(query);
        return Result.success(baseService.removeById(id));
    }

    @ApiOperation("导入Excel模版下载")
    @ApiImplicitParam(name = "gridId", value = "gridId", required = true, dataType = "String", paramType = "path")
    @GetMapping ("/importExcelTemplateDownload/{gridId}")
    public void importExcelTemplateDownload(HttpServletResponse response,@PathVariable String gridId) throws IOException {
//        // 获取网格id
//        String gridId = RequestBuffUtil.getGridId();
        // 获取别名信息
        LinkedHashMap<String, String> aliasMap = new LinkedHashMap<>();
        gridService.getImportField(gridId, aliasMap, null);
        // 导出为xlsx
        ExcelTool.exportExcel(response, aliasMap, null, "template");
    }

    @ApiOperation("导入Excel")
    @PostMapping ("/importExcel")
    public Result<FaSysImportRecord> importExcel(@RequestParam("file") MultipartFile file) throws IOException {
        // 保存文件
        FaSysFile importFile = fileService.upload(file);
        //通过sheet编号获取
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        // 获取网格id
        String gridId = RequestBuffUtil.getGridId();
        // 获取网格信息
        FaSysGrid grid = gridService.getById(gridId);
        // 获取导入配置
        String importJson = grid.getImportJson();
        JSONObject importJsonObj = JSONUtil.parseObj(importJson);
        // 获取别名信息
        HashMap<String, String> aliasMap = new HashMap<>();
        // 过滤无需导入的字段
        List<JSONObject> fieldList = new ArrayList<>();
        gridService.getImportField(gridId, aliasMap, fieldList);
        // 设置别名
        reader.setHeaderAlias(aliasMap);
        // 格式化数据
        List<JSONObject> all = reader.readAll(JSONObject.class);
        if(all.size() > importJsonObj.getInt("num")){
            throw new ServiceException(StrUtil.format("导入数据 {} 超出最大限制 {}",all.size(), importJsonObj.getInt("num")));
        }
        // 创建临时文件
        File tempFile = FileUtil.createTempFile(".xlsx",true);
        FileUtil.writeFromStream(file.getInputStream(), tempFile, true);
        ExcelWriter writer = ExcelUtil.getWriter(tempFile);
        // 设置写入内容统一样式
        CellStyle cellStyle = writer.getCellStyle();
        // 设置字体红色
        Font font = writer.createFont();
        font.setColor(Font.COLOR_RED);
        cellStyle.setFont(font);
        // 取消默认边框
        cellStyle.setBorderBottom(BorderStyle.NONE);
        cellStyle.setBorderTop(BorderStyle.NONE);
        cellStyle.setBorderLeft(BorderStyle.NONE);
        cellStyle.setBorderRight(BorderStyle.NONE);
        // 获取转换选项数据
        HashMap<String, List<OptionsDto>> optionMap = new HashMap<>();
        // 获取不允许重复字段列表
        HashMap<String, List<Object>> repeatFields = new HashMap<>();
        for (JSONObject entries : fieldList) {
            String field = entries.getStr("field");
            JSONObject type = entries.getJSONObject("type");
            String typeValue = type.getStr("value");
            if(typeValue.equals("select")){
                String optionId = type.getByPath("select.optionId").toString();
                List<OptionsDto> options = optionService.getOptions(optionId);
                optionMap.put(field, options);
            }
            // 重复数据判断
            JSONObject rule = entries.getJSONObject("serviceRule");
            String repeat = rule.getStr("repeat");
            if("false".equals(repeat)){
                List<Object> fieldValues = new ArrayList<>();
                all.stream().forEach(t->{
                    fieldValues.add(t.getStr(field));
                });
                repeatFields.put(field, fieldValues);
            }
        }
        // 参数校验
        AtomicInteger errNum = new AtomicInteger();
        for (int i = 0; i < all.size(); i++) {
            JSONObject t = JSONUtil.parseObj(all.get(i));
            // 获取横坐标
            int X = (i+2);
            for (int index = 0; index < fieldList.size(); index++) {
                JSONObject fieldJsonObj = fieldList.get(index);
                String field = fieldJsonObj.getStr("field");
                // 规则校验
                JSONObject rule = fieldJsonObj.getJSONObject("serviceRule");
                String required = rule.getStr("required");
                // 获取字段值
                Object fieldValue = t.get(field);
                // 计算当前只坐标
                String Y = String.valueOf((char)(65+index));
                // 合并坐标
                String coordinate = Y.concat(String.valueOf(X));
                if("true".equals(required)){
                    if(Objects.isNull(fieldValue) || StrUtil.isBlank(fieldValue.toString())){
                        errNum.getAndIncrement();
                        // 写入校验结果
                        writer.writeCellValue(coordinate,"必填");
                        continue;
                    }
                    if(fieldValue.equals(false)){
                        throw new ServiceException("未找到设置为该别名的列 ".concat(field));
                    }
                } else if (Objects.isNull(fieldValue) || StrUtil.isBlank(fieldValue.toString())) {
                    // 值为空，且非必填，跳过以下教校验
                    continue;
                }
                // 是否重复
                String repeat = rule.getStr("repeat");
                if("false".equals(repeat)){
                    // 查询表格内是否存在重复元素
                    List<Object> fieldValues = repeatFields.get(field);
                    // 获取重复值Y坐标
                    List<Integer> coordinateY = new ArrayList<>();
                    IntStream.range(0, fieldValues.size()).forEach(fieldValuesIndex-> {
                        Integer zbY = fieldValuesIndex+2;
                        if(fieldValues.get(fieldValuesIndex).equals(fieldValue) && !zbY.equals(X)){
                            coordinateY.add(zbY);
                        }
                    });
                    if(!coordinateY.isEmpty()){
                        errNum.getAndIncrement();
                        // 存在重复数据
                        writer.writeCellValue(coordinate,fieldValue.toString().concat(StrUtil.format("(与第 ${} 行数据重复)",coordinateY.toString())));
                        continue;
                    } else {
                        // 查询数据库是否存在重复元素
                        boolean ifExist = baseService.ifExist(StrUtil.toUnderlineCase(field), fieldValue);
                        if(ifExist){
                            errNum.getAndIncrement();
                            writer.writeCellValue(coordinate,fieldValue.toString().concat("(数据已存在)"));
                            continue;
                        }
                    }

                }
                // 选项转换
                JSONObject type = fieldJsonObj.getJSONObject("type");
                String typeValue = type.getStr("value");
                if("select".equals(typeValue)){
                    List<OptionsDto> optionsDtos = optionMap.get(field);
                    boolean ifExit = false;
                    for (OptionsDto optionsDto : optionsDtos) {
                        if(optionsDto.getLabel().equals(fieldValue)){
                            ifExit = true;
                        }
                    }
                    if(!ifExit){
                        errNum.getAndIncrement();
                        // 写入校验结果
                        writer.writeCellValue(coordinate,fieldValue.toString().concat("(未找到该选项匹配的值)"));
                    }
                }

            }
        }
        // 创建上传记录
        FaSysImportRecord faSysImportRecord = new FaSysImportRecord();
        // 判断校验是否通过
        if(errNum.get()>0){
            // 将添加校验结果的表格保存
            writer.flush(tempFile);
            writer.close();
            // 创建校验文件名称
            String dateStr = DateUtil.format(new Date(), "yyyyMMddHHmmss");
            FaSysFile checkFile = fileService.upload(tempFile,dateStr.concat("-checkResult-").concat(file.getOriginalFilename()));
            faSysImportRecord .setCheckFileId(checkFile.getId())
                    .setCheckFileUrl(checkFile.getUrl())
                    .setCheckResult(0);
        }else{
            faSysImportRecord.setCheckResult(1);
        }
        faSysImportRecord.setGridId(gridId)
                .setImportFileId(importFile.getId())
                .setImportFileUrl(importFile.getUrl());
        importRecordService.save(faSysImportRecord);
        // 返回参数校验结果
        return Result.success(faSysImportRecord);
    }

    @ApiOperation("导入Excel数据")
    @ApiImplicitParam(name = "importRecordId", value = "importRecordId", required = true, dataType = "String", paramType = "path")
    @GetMapping ("/importExcelData/{importRecordId}")
    public Result importExcelData(@PathVariable String importRecordId) {
        // 获取导入记录
        FaSysImportRecord importRecord = importRecordService.ifNotExist(FaSysImportRecord::getId, importRecordId, "异常!导入记录不存在!");
        // 判断校验是否通过
        if(importRecord.getCheckResult().equals(0)){
            throw new ServiceException("异常!数据校验未通过!");
        }
        if(importRecord.getImportResult().equals(1)){
            throw new ServiceException("异常!该文件重复导入!");
        }
        // 获取导入文件系统路径
        FaSysFile faSysFile = fileService.getById(importRecord.getImportFileId());
        // 提取导入Excel文件数据
        ExcelReader reader = ExcelUtil.getReader(new File(faSysFile.getPath()));
        // 别名信息
        HashMap<String, String> aliasMap = new HashMap<>();
        // 过滤无需导入的字段
        List<JSONObject> fieldList = new ArrayList<>();
        gridService.getImportField(importRecord.getGridId(), aliasMap, fieldList);
        // 设置别名
        reader.setHeaderAlias(aliasMap);
        // 格式化数据
        List<JSONObject> all = reader.readAll(JSONObject.class);
        for (JSONObject entries : fieldList) {
            String field = entries.getStr("field");
            JSONObject type = entries.getJSONObject("type");
            String typeValue = type.getStr("value");
            if(typeValue.equals("select")){
                String optionId = type.getByPath("select.optionId").toString();
                List<OptionsDto> options = optionService.getOptions(optionId);
                for (int i = 0; i < all.size(); i++) {
                    JSONObject t = JSONUtil.parseObj(all.get(i));
                    // 获取字段值
                    Object fieldValue = t.get(field);
                    if(Objects.nonNull(fieldValue) && StrUtil.isNotBlank(fieldValue.toString())){
                        List<OptionsDto> collect = options.stream().filter(item -> item.getLabel().equals(fieldValue)).collect(Collectors.toList());
                        t.set(field, collect.get(0).getValue());
                    }
                    all.set(i, t);
                }
            }
        }

        List<T> dataList = all.stream().map(t-> JSONUtil.toBean(t,( Class<T>)getEClass())).collect(Collectors.toList());
        // 钩子
        dataList = importExcelDataBefore(dataList);
        // 导入
        baseService.saveBatch(dataList);
        // 编辑导入结果
        importRecordService.updateById(FaSysImportRecord::getImportResult,1,importRecordId);
        return Result.success();
    }

    /**
     * 导入数据之前的钩子函数
     * @param dataList
     * @return 必须返回数据
     */
    public List<T> importExcelDataBefore(List<T> dataList){
        // 对数据进行处理后再返回
        return dataList;
    }

    @ApiOperation("导出")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "gridId", value = "网格id", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "query", value = "查询参数", required = true, dataType = "T", paramType = "body")
    })
    @PostMapping("/exportExcel/{gridId}")
    public void exportExcel(HttpServletResponse response, @PathVariable String gridId, @RequestBody T query) throws IOException {
        FaSysGrid grid = gridService.getById(gridId);
        // 查询数据，此处待优化，应和页面查询结果一致
        IPage<T> page = baseService.page(new Page(1, Integer.MAX_VALUE), query, grid);
        // 导出数据
        LinkedHashMap<String, String> aliasMap = new LinkedHashMap<>();
        gridService.getExportField(gridId, aliasMap);
        // 写入数据
        List<Object> datas = new ArrayList<>(page.getRecords());
        // 导出为xlsx
        ExcelTool.exportExcel(response, aliasMap, datas, "excel");
    }

    /**
     * 排序交换
     * @param moveNode 移节点
     * @param targetNode 目标节点
     */
    private void sortExchange(T moveNode, T targetNode){
        // 与目标对象交换排序
        Object moveSort = ReflectUtil.getFieldValue(moveNode, "sort");
        Object targetSort = ReflectUtil.getFieldValue(targetNode, "sort");
        ReflectUtil.setFieldValue(moveNode,"sort",targetSort);
        ReflectUtil.setFieldValue(targetNode,"sort",moveSort);
        updateById(moveNode);
        updateById(targetNode);
    }

    /**
     * 越权检查
     * @param query
     */
    private void overstepCheck(T query){
    }

    public Class<?> getEClass() {

        //get the Class object of this own class
        Class<?> thisClass = this.getClass();

        //get the Type Object of supper class
        Type superClassType = thisClass.getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType)superClassType;

        //get the Generic Type array
        Type[] genTypeArr = pt.getActualTypeArguments();
        Type genType = genTypeArr[0];
        if (false == genType instanceof Class){
            return Object.class;
        }

        return (Class<Object>) genType;
    }

    public boolean existfield(String fieldName){
        Class<?> eClass = getEClass();
        try {
            eClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            return false;
        }
        return true;
    }
}
